package com.fly.quick.web;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import com.fly.core.utils.Executor;
import com.fly.core.utils.XmlUtils;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Api(tags = "Jar源码异步接口")
@RestController
@RequestMapping("/depend/asyn")
public class AsynDependController
{
    private String mvnRepoPath;
    
    @PostConstruct
    public void init()
    {
        try
        {
            String mavenHome = Executor.execute("mvn -v").stream().filter(r -> r.startsWith("Maven home:")).map(arg -> StringUtils.substringAfter(arg, "Maven home:")).collect(Collectors.joining());
            String settings = mavenHome.trim() + "/conf/settings.xml";
            log.info("settings Path: {}", settings);
            String xmlContent = FileUtils.readFileToString(new File(settings), StandardCharsets.UTF_8.toString());
            Properties prop = XmlUtils.xmlToProperties(xmlContent);
            mvnRepoPath = prop.getProperty("localRepository");
            if (StringUtils.isBlank(mvnRepoPath))
            {
                mvnRepoPath = System.getProperty("user.home") + "/.m2/repository";
            }
            log.info("mvnRepo Path: {}", mvnRepoPath);
        }
        catch (IOException e)
        {
            log.error(e.getMessage(), e);
        }
    }
    
    /**
     * 测试文件请选择：src\main\resources\test\pomx.ml<br>
     * maven本地仓库地址请在application.yml文件中配置mvnRepoPath值
     * 
     * @param file
     * @return
     * @throws IOException
     */
    @ApiOperationSupport(order = 10)
    @ApiOperation(value = "pom文件提交")
    @PostMapping(value = "/pom", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseBodyEmitter pom(MultipartFile file)
        throws IOException
    {
        ResponseBodyEmitter responseBodyEmitter = new ResponseBodyEmitter();
        Executors.newFixedThreadPool(5).submit(() -> {
            try
            {
                if (file == null || !file.getOriginalFilename().endsWith(".xml"))
                {
                    responseBodyEmitter.send("文件为空或文件格式不是xml");
                    responseBodyEmitter.complete();
                }
                else
                {
                    String path = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss");
                    File rootDir = new File("upload/" + path);
                    File dest = new File(rootDir.getCanonicalPath() + "/" + file.getOriginalFilename());
                    dest.getParentFile().mkdirs();
                    file.transferTo(dest.getAbsoluteFile());
                    responseBodyEmitter.send("保存pom.xml成功");
                    responseBodyEmitter.send("\n");
                    
                    // 运行package命令，收集jar到lib
                    String pomPath = dest.getAbsolutePath();
                    log.info("pom.xml 文件路径：{}", pomPath);
                    String command = "mvn clean package -f " + pomPath;
                    responseBodyEmitter.send("执行mvn clean package");
                    responseBodyEmitter.send("\n");
                    
                    // 输出mvn命令日志
                    String[] cmd = SystemUtils.IS_OS_WINDOWS ? new String[] {"cmd", "/c", command} : new String[] {"/bin/sh", "-c", command};
                    Process ps = Runtime.getRuntime().exec(cmd);
                    try (BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())))
                    {
                        String line;
                        while ((line = br.readLine()) != null)
                        {
                            responseBodyEmitter.send(line);
                            responseBodyEmitter.send("\n");
                        }
                    }
                    
                    // 收集sources
                    String srcCommand = "mvn dependency:sources -DdownloadSources=true -f " + pomPath;
                    List<String> listData = Executor.execute(srcCommand).stream().filter(d -> StringUtils.contains(d, ":jar:sources:")).collect(Collectors.toList());
                    copyResource(listData, mvnRepoPath, path);
                    responseBodyEmitter.send("copyResource success!");
                    responseBodyEmitter.send("\n");
                    responseBodyEmitter.complete();
                }
            }
            catch (IOException e)
            {
            }
        });
        return responseBodyEmitter;
    }
    
    /**
     * 拷贝jar源码到/target/sources目录下
     * 
     * @param listData 源码信息
     * @param mvnRepoPath maven本地仓库目录
     * @param targetPath pom所在的项目目录
     * @throws IOException
     */
    private void copyResource(List<String> listData, String mvnRepoPath, String targetPath)
        throws IOException
    {
        File directory = new File("upload//" + targetPath + "//target//sources");
        StopWatch watch = new StopWatch();
        watch.start();
        listData.forEach(item -> {
            if (item.contains(":jar:sources:"))
            {
                String[] array = StringUtils.substringAfterLast(item, " ").split(":");
                String groupId, artifactId, version, path;
                if (array.length >= 5)
                {
                    try
                    {
                        groupId = array[0];
                        artifactId = array[1];
                        version = array[4];
                        path = String.format("%s/%s/%s/%s/%s-%s-sources.jar", mvnRepoPath, groupId.replace(".", "/"), artifactId, version, artifactId, version);
                        log.info("------ path: {}   ", path);
                        FileUtils.copyFileToDirectory(new File(path), directory);
                    }
                    catch (IOException e)
                    {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        });
        watch.stop();
        log.info("Run cost time ms: {}", watch.getTime(TimeUnit.MILLISECONDS));
        if (SystemUtils.IS_OS_WINDOWS)
        {
            Runtime.getRuntime().exec("cmd /c start " + directory.getParentFile().getPath());
        }
        FileUtils.forceDeleteOnExit(directory);
    }
}
